#ifndef TIEC_COMPONENT_H
#define TIEC_COMPONENT_H

#include "data.h"
#include "foundation.h"
#include "tree.h"
#include "tree_path.h"

#define COMPONENT_NAME(cls) kComponent##cls
#define DECL_COMPONENT_TYPE(cls) String cls::getType() { \
  return COMPONENT_NAME(cls); \
}
#define DECL_COMPONENT_NAME(cls) static constexpr const char* COMPONENT_NAME(cls) = #cls;
#define DEF_COMPONENT_FACTORY(cls) static PTR<cls> instance(const PTR<Context>& context);
#define DECL_COMPONENT_FACTORY(cls) PTR<cls> cls::instance(const PTR<Context>& context) { \
  PTR<cls> instance = context->getComponent<cls>(); \
  if (instance == nullptr) { \
    instance = MAKE_PTR<cls>(); \
    context->addComponent<cls>(instance); \
  } \
  return instance; \
}
#define DECL_COMPONENT_FACTORY_WITH_CONTEXT(cls) PTR<cls> cls::instance(const PTR<Context>& context) { \
  PTR<cls> instance = context->getComponent<cls>(); \
  if (instance == nullptr) { \
    instance = MAKE_PTR<cls>(context); \
    context->addComponent<cls>(instance); \
  } \
  return instance; \
}
#define DEF_ANNOTATION_CLASS(class_name) \
  class class_name : public AnnotationProcessor { \
    TaskKind getTaskKind() override; \
    Modifiers getLevelModifiers() override; \
    ValidationResult argIsExpected(const PTR<ExpressionTree>& arg, const PTR<Context>& context) override; \
    ProcessResult processTree(const PTR<AnnotatedTree>& tree, const PTR<ExpressionTree>& arg, const PTR<Context>& context) override; \
  };
#define DECL_ANNOTATION_NO_ARG(class_name, task_kind, levels) \
  TaskKind class_name::getTaskKind() { \
    return task_kind; \
  } \
  Modifiers class_name::getLevelModifiers() { \
    return Modifiers{levels}; \
  } \
  ValidationResult class_name::argIsExpected(const PTR<ExpressionTree>& arg, const PTR<Context>& context) { \
    return ValidationResult::ArgUnExpected; \
  }
#define DECL_ANNOTATION_SIMPLE(class_name, task_kind, levels) \
  TaskKind class_name::getTaskKind() { \
    return task_kind; \
  } \
  Modifiers class_name::getLevelModifiers() { \
    return Modifiers{levels}; \
  }

namespace NS_TIEC {
  /// 编译器组件
  class Component {
  public:
    /// 组件类型
    /// \return 组件的名称(type)
    virtual String getType() = 0;
  };

  /// 组件的Key模板
  template<typename T>
  size_t keyOfComponent() {
    return typeid(T).hash_code();
  };

  /// 编译器组件上下文
  class Context {
  public:
    ~Context();

    /// 获取上下文中指定编译器组件
    /// \tparam T 组件类型
    /// \return 对应的编译器组件，如果找不到则返回空指针
    template<class T>
    PTR<T> getComponent() {
      auto key = keyOfComponent<T>();
      if (components_.contains(key)) {
        return std::static_pointer_cast<T>(components_[key]);
      }
      return nullptr;
    }

    /// 获取上下文中指定编译器组件，如果没有则执行创建
    /// \tparam T 组件类型
    /// \param supplier 创建组件的函数
    /// \return 对应的编译器组件，如果找不到则返回空指针
    template<class T>
    PTR<T> getComponentOrCreate(FUNCTION<PTR<T>()> supplier) {
      auto key = keyOfComponent<T>();
      if (!components_.contains(key)) {
        PTR<T> instance = supplier();
        components_.put(key, instance);
      }
      return std::static_pointer_cast<T>(components_[key]);
    }

    /// 获取上下文中指定编译器组件，如果没有则自动创建为智能指针
    /// \tparam T 组件类型
    /// \return 对应的编译器组件
    template<class T>
    PTR<T> getComponentOrCreateDefault() {
      auto key = keyOfComponent<T>();
      if (!components_.contains(key)) {
        PTR<T> instance = MAKE_PTR<T>();
        components_.put(key, instance);
      }
      return std::static_pointer_cast<T>(components_[key]);
    }

    /// 在上下文中注册一个编译器组件
    /// \tparam T 组件类型
    /// \param component 编译器组件
    template<class T>
    void addComponent(PTR<T>& component) {
      auto key = keyOfComponent<T>();
      components_.put(key, component);
    }

    /// 判断在上下文中是否存在指定组件
    /// \tparam T 组件类型
    /// \return 如果存在则返回true
    template<class T>
    bool hasComponent() {
      auto key = keyOfComponent<T>();
      return components_.contains(key);
    }

  private:
    HashMap<size_t, PTR<Component>> components_;
  };

  /// 编译器支持的输出平台枚举
  enum struct TargetPlatform {
    kUndefined = 0,
    kAndroid,
    kHarmony,
    kLinux,
    kWindows,
    kIOS,
    kApple,
    kHtml,
  };

  /// 编译选项
  class Options : public Component {
  public:
    static Options kDefault;

    /// 默认包名
    WString package_name;
    /// 输出路径
    String output_dir;
    /// 行号表输出路径
    String line_map_path;
    /// debug工具包输出路径
    String debug_tool_path;
    /// debug目标平台
    String debug_platform;
    /// 是否debug模式
    bool debug{false};
    /// 是否进行代码优化
    bool optimize{false};
    /// 是否进行硬输出，所有用到的文件都拷贝到输出目录，而不是使用地址引用
    bool hard_mode{false};
    /// 是否支持树形源文件组合
    bool enable_tree_source{false};
    /// 是否支持嵌入式代码
    bool enable_code{true};
    /// 是否支持顶级语句，即在类之外编写语句
    bool enable_top_statements{true};
    /// 泛型是否使用生成新类的方式进行实现
    bool template_type_newclass{false};
    /// 日志输出级别
    LogLevel log_level {LogLevel::kLevelDebug};
    /// 输出的目标平台
    TargetPlatform platform {TargetPlatform::kUndefined};

    String getType() override;

    DEF_COMPONENT_FACTORY(Options)
  };

  /// Name对象池组件
  class NameTable : public Component {
  public:
    PTR<Name> error;
    PTR<Name> tiecode_basic;
    PTR<Name> null_literal;
    PTR<Name> this_object;
    PTR<Name> super_object;
    PTR<Name> code_ref_this;
    PTR<Name> type_string;
    PTR<Name> type_int;
    PTR<Name> type_long;
    PTR<Name> type_float;
    PTR<Name> type_double;
    PTR<Name> type_bool;
    PTR<Name> type_char;
    PTR<Name> type_byte;
    PTR<Name> type_variant;
    PTR<Name> const_file;
    PTR<Name> const_color;
    PTR<Name> op_array_access;
    PTR<Name> op_array_assign;
    PTR<Name> op_equals;
    PTR<Name> op_question;
    PTR<Name> op_plus;
    PTR<Name> op_minus;
    PTR<Name> op_mul;
    PTR<Name> op_div;
    PTR<Name> op_xor;
    PTR<Name> op_mod;
    PTR<Name> op_double_equals;
    PTR<Name> op_not_equals;
    PTR<Name> op_less;
    PTR<Name> op_greater;
    PTR<Name> op_less_equals;
    PTR<Name> op_greater_equals;

    NameTable();

    /// 通过文本取得一个唯一地址的Name指针
    /// @param str 文本内容
    /// @return 只要文本内容值相同，会始终指向同一个Name
    PTR<Name> getName(const WString& str);

    /// 判断指定Name是否为基本类型名称
    /// @param name 名称
    bool isBasicTypeName(const PTR<Name>& name) const;

    String getType() override;
    DEF_COMPONENT_FACTORY(NameTable)
  private:
    HashMap<WString, PTR<Name>> name_map_;
  };

  /// 诊断信息处理器接口
  class DiagnosticHandler {
  public:
    /// 输出诊断信息
    /// \param diagnostic 诊断信息详情
    virtual void report(Diagnostic& diagnostic) = 0;
  };

  class StdOutDiagnosticHandler : public DiagnosticHandler {
    public:
    virtual void report(Diagnostic& diagnostic) override;
  };

  /// 消息收集器
  class Messages : public Component {
  public:
    Messages();

    /// 收集提示信息级别的日志
    /// \param message 信息文本内容
    virtual void info(const String& message);

    /// 收集警告级别的日志
    /// \param message 信息文本内容
    virtual void warning(const String& message);

    /// 收集错误级别的日志
    /// \param message 信息文本内容
    virtual void error(const String& message);

    /// 收集致命错误级别的日志
    /// \param message 信息文本内容
    virtual void fatalError(const String& message);

    /// 收集诊断信息
    /// \param diagnostic 诊断信息
    virtual void diagnostic(Diagnostic& diagnostic);

    /// 当前是否有致命错误，如果有，后续流程将停止进行
    virtual bool hasFatalError();

    /// 获取收集到的错误数量
    virtual UInt32 errorCount();

    /// 获取收集到的警告数量
    virtual UInt32 warningCount();

    /// 设置诊断信息输出器
    /// @param handler 诊断信息输出器实现
    void setDiagnosticHandler(const PTR<DiagnosticHandler>& handler);

    String getType() override;
    DEF_COMPONENT_FACTORY(Messages)
  private:
    UInt32 error_count_{0};
    UInt32 warning_count_{0};
    bool fatal_mark_{false};
    PTR<DiagnosticHandler> diagnostic_handler_;
    LogLevel log_level_ {LogLevel::kLevelDebug};
  };

  /// 源文件管理
  class SourceManager : public Component {
  public:
    /// 添加一个源文件
    /// @param source 源文件
    void addSource(PTR<Source>& source);

    /// 添加多个源文件
    /// @param sources 源文件列表
    void addSourceList(const List<PTR<Source>>& sources);

    /// 通过Uri获取源文件
    /// @param uri 源文件的Uri
    PTR<Source> getSource(const Uri& uri);

    /// 获取某个子树源文件的根节点源文件
    /// @param source 子树源文件
    /// @return 根节点源文件
    PTR<Source> getSourceRoot(const PTR<Source>& source) const;

    /// 获取源文件集合
    /// @return 当前编译环境下所有源文件
    Set<PTR<Source>> getSourceSet() const;

    /// 遍历所有源文件
    /// @param consumer 源文件遍历函数
    void forEachSource(VOID_FUNCTION(const PTR<Source>& source) consumer) const;

    /// 根据Source获取其ID
    /// @param source Source实例
    /// @return
    Int64 getIdForSource(const PTR<Source>& source);

    /// 根据ID获取对应的Source
    /// @param id Source的Id
    /// @return
    PTR<Source> getSourceById(const Int64 id) const;

    /// 根据ID获取对应的Source Uri
    /// @param id Source的Id
    /// @return
    Uri getSourceUriById(const Int64 id) const;

    String getType() override;
    DEF_COMPONENT_FACTORY(SourceManager)
  private:
    Set<PTR<Source>, SourcePtrHash, SourcePtrEqual> sources_;
    // 这里存每个子树源文件指向编译单元根节点源文件的索引，便于直接索引到根节点，重建整个语法树
    HashMap<PTR<Source>, PTR<Source>, SourcePtrHash, SourcePtrEqual> source_root_map_;
    // 存Source和id的映射
    HashMap<PTR<Source>, Int64, SourcePtrHash, SourcePtrEqual> source_id_map_;
    HashMap<Int64, PTR<Source>> id_source_map_;
    Int64 source_id_used_ {0};

    void registrySourceRootMapping(const PTR<Source>& source, const PTR<Source>& root);
  };

  /// 编译单元合并器，源文件可以为树形结构组合，当启用树形源文件时，可以将多个树形源文件中所有编译单元组合到根节点形成完整的编译单元，
  /// 组合的编译单元必须有层级规范，顶层必须为类定义、下一级必须是方法、事件，再往下一级只能是语句，语句可以无限层级嵌套
  class CompilationUnitMerger : public Component {
  public:
    explicit CompilationUnitMerger(const PTR<Context>& context);

    /// 将编译单元中顶级语句合成到特定的方法或事件（比如安卓平台合成到“事件 窗口:创建完毕()”）
    /// @param root 根节点编译单元
    virtual void synthesizeTopLevelStatements(const PTR<CompilationUnitTree>& root) const;

    /// 将子编译单元合并到父编译单元
    /// @param parent 父节点
    /// @param child 子节点
    void merge(const PTR<CompilationUnitTree>& parent, const PTR<CompilationUnitTree>& child) const;

    String getType() override;
    DEF_COMPONENT_FACTORY(CompilationUnitMerger)
  protected:
    WPTR<Messages> messages_;
    WPTR<SourceManager> sources_;

    void mergeMemberToTopLevel(const PTR<CompilationUnitTree>& parent, const PTR<CompilationUnitTree>& child) const;
    void mergeStatementsToMember(const PTR<CompilationUnitTree>& parent, const PTR<CompilationUnitTree>& child) const;
    void mergeStatementsToStatement(const PTR<CompilationUnitTree>& parent, const PTR<CompilationUnitTree>& child) const;
    static const char* getUnitKindDescription(const CompilationUnitKind kind);
  };

  // 语法树表
  class TreeTable : public Component {
  public:
    /// @brief 插入或更新某个源文件的语法树，由于源文件是树形结构，所以一般每次更新都会调用多次
    /// @param source 源文件
    /// @param tree 根节点
    void addOrUpdateTree(const PTR<Source>& source, const PTR<CompilationUnitTree>& tree);

    /// @brief 移除某个源文件的语法树，由于源文件是树形结构，所以一般每次更新都会调用多次
    /// @param source 源文件
    void removeTree(const PTR<Source>& source);

    /// 获取源文件对应的语法树
    /// @param source 源文件
    PTR<CompilationUnitTree> getTree(const PTR<Source>& source) const;

    /// @brief 遍历TreeTable
    /// @param consumer 遍历函数
    void forEach(FUNCTION<void(const PTR<Source>&, PTR<CompilationUnitTree>&)> consumer);

    /// @brief 遍历TreeTable，遇到return true时停止遍历
    /// @param consumer 遍历函数
    void forEachUntil(FUNCTION<bool(const PTR<Source>&, PTR<CompilationUnitTree>&)> consumer);

    /// 存放一组类名到类的键值对
    /// @param full_name 完整类名
    /// @param root_tree 类所处编译单元
    /// @param class_tree 类定义
    void storeClassWithUnit(const PTR<Name>& full_name, const PTR<CompilationUnitTree>& root_tree, const PTR<ClassTree>& class_tree);

    /// 通过完整类名取得其所定义的ClassTree和所在编译单元
    /// @param full_name 完整类名
    PAIR<PTR<CompilationUnitTree>, PTR<ClassTree>> getClassWithUnit(const PTR<Name>& full_name) const;

    String getType() override;
    DEF_COMPONENT_FACTORY(TreeTable)
  private:
    // 这里存的 CompilationUnitTree 是经过多个子树源文件合并之后的Tree，不存独立的Tree，便于重建整个编译单元语法树
    HashMap<PTR<Source>, PTR<CompilationUnitTree>, SourcePtrHash, SourcePtrEqual> source_uint_map_;
    // 存完整类名到 键值对<编译单元,类>，仅在符号填充时做临时存储使用，并不稳定，不可过度依赖此数据
    HashMap<PTR<Name>, PAIR<PTR<CompilationUnitTree>, PTR<ClassTree>>, NamePtrHash, NamePtrEqual> name_class_map_;
  };

  // 符号表
  class SymbolTable : public Component {
  public:
    // 全局的基础父类
    PTR<ClassSymbol> global_super_class;
    // 基础类型Type
    PTR<ClassType> type_int;
    PTR<ClassType> type_long;
    PTR<ClassType> type_char;
    PTR<ClassType> type_bool;
    PTR<ClassType> type_byte;
    PTR<ClassType> type_float;
    PTR<ClassType> type_double;
    PTR<ClassType> type_string;
    PTR<VariantType> type_variant;
    PTR<VoidType> type_void;
    PTR<NullType> type_null;

    explicit SymbolTable(const PTR<Context>& context);

    /// @brief 添加一个包名Symbol
    /// @param pkg 包名Symbol定义
    void definePackage(const PTR<PackageSymbol>& pkg);

    /// @brief 添加一个类Symbol，如果已有重名的，则添加到List
    /// @param klass 类Symbol定义
    void defineClass(const PTR<ClassSymbol>& klass);

    /// @brief 实现一个模板类
    /// @param template_name 模板类完整类名
    /// @param key 模板实现参数的key
    /// @param impl_symbol 具体实现的ClassSymbol
    void implTemplateClass(const PTR<Name>& template_name, const WString& key, const PTR<ClassSymbol>& impl_symbol);

    /// 获取模板类型实现的Class
    /// @param template_name 模板类型完整类名
    /// @param key 模板实现参数的key
    /// @return 具体实现的ClassSymbol
    PTR<ClassSymbol> getTemplateImplClass(const PTR<Name>& template_name, const WString& key) const;

    /// 检查class是否为基本类型定义类，如果是则初始化基本类型
    /// @param klass 要处理的ClassSymbol
    void checkBasicTypeClass(const PTR<ClassSymbol>& klass);

    /// 根据基本类型标识符名称获取基本类型Type定义
    /// @param name 基本类型名称
    PTR<ClassType> getBasicTypeByName(const PTR<Name>& name) const;

    /// 根据包名获取PackageSymbol
    /// @param name 包名
    PTR<PackageSymbol> getPackage(const PTR<Name>& name) const;

    /// 根据包名和类名获取 ClassSymbol
    /// @param pkg_name 包名
    /// @param name 类名
    PTR<ClassSymbol> getClass(const PTR<Name>& pkg_name, const PTR<Name>& name) const;

    /// 根据类名获取名称为指定文本的 ClassSymbol
    /// @param name 类名
    PTR<ClassSymbol> getFirstClass(const PTR<Name>& name) const;

    /// 根据类名获取所有相同名称的ClassSymbol
    /// @param name 类名
    List<PTR<ClassSymbol>> getClasses(const PTR<Name>& name) const;

    /// 移除某个源文件定义的所有Symbol
    /// @param source 源文件
    void removeSymbolWithSource(const PTR<Source>& source);

    /// 遍历当前环境中每一个ClassSymbol
    /// @param consumer 遍历函数
    void forEachClass(VOID_FUNCTION(const PTR<ClassSymbol>& symbol) consumer);

    String getType() override;
    DEF_COMPONENT_FACTORY(SymbolTable)
  private:
    HashMap<PTR<Name>, PTR<PackageSymbol>, NamePtrHash, NamePtrEqual> package_map_;
    HashMap<PTR<Name>, List<PTR<ClassSymbol>>, NamePtrHash, NamePtrEqual> class_map_;
    // 存每个模板类的实现（实现类型key to ClassSymbol），为什么不存 PTR<ClassSymbol>，因为ClassSymbol可能在IDE服务时实时更新造成地址改变，但完整类名一定是不变的
    HashMap<PTR<Name>, HashMap<WString, PTR<ClassSymbol>>, NamePtrHash, NamePtrEqual> template_impl_map_;
    PTR<SourceManager> sources_;
    PTR<NameTable> names_;
  };

  /// 编译器通用规范的名称重整器，用于为Symbol生成编译输出名称，不使用原有中文名
  class NameMangler : public Component {
  public:
    /// 为指定Symbol生成输出名
    /// @param symbol 当前要处理的Symbol
    /// @return Symbol编译输出时所需要使用的名称
    WString mangle(const PTR<Symbol>& symbol);

    /// 随机生成一个名称，用作编译器生成的临时变量名称
    WString randName();

    /// 判断用户使用的输出名是否合法
    /// @param name 用户指定的输出名
    bool nameIsExpected(const WString& name);

    /// 加载之前生成过的名称映射表进行复用，保证本次编译输出名称与上一次一致
    /// @param file 名称映射文件
    void loadMapping(const File& file);

    /// 将输出名映射保存到指定文件，便于下次复用
    /// @param file
    void generateMapping(const File& file);
  private:
    UInt64 name_index_ {1};
  };

  /// 注解处理器注解参数检查结果
  enum struct ValidationResult {
    /// 参数符合
    Pass = 0,
    /// 不应该有参数
    ArgUnExpected,
    /// 缺少参数
    ArgMissed,
    /// 参数类型不匹配
    TypeNotMatched,
    /// 找不到符号
    SymbolNotFound,
  };

  /// 注解处理器处理返回结果
  enum struct ProcessResult {
    /// 没有做出什么修改，编译器无需重新分析任何东西
    ModifiedNone = 0,
    /// 修改了当前注解的语法树，返回该结果，编译器将重新对当前语法树进行符号填充和语法树标注
    ModifiedCurrentTree,
    /// 修改了当前所处类，返回该结果，编译器将重新对当前整个类重新进行符号填充和语法树标注
    ModifiedCurrentClass,
    /// 修改了所有语法树，需要编译器对整个编译环境中所有语法树重新进行符号填充和语法树标注
    ModifiedAll,
  };

  /// 注解处理器
  class AnnotationProcessor {
  public:
    /// 注解的处理阶段
    virtual TaskKind getTaskKind() = 0;

    /// 获取注解处理器支持的成员级别
    virtual Modifiers getLevelModifiers() = 0;

    /// 判断注解参数是否符合预期
    /// @param arg 注解参数表达式
    /// @param context 当前编译器上下文
    virtual ValidationResult argIsExpected(const PTR<ExpressionTree>& arg, const PTR<Context>& context) = 0;

    /// 处理被注解的语法树
    /// @param tree 被注解的语法树
    /// @param arg 注解的参数
    /// @param context 编译器上下文
    /// @return 返回处理结果，具体可参见 {@struct ProcessResult}
    virtual ProcessResult processTree(const PTR<AnnotatedTree>& tree, const PTR<ExpressionTree>& arg, const PTR<Context>& context) = 0;
  };

  /// 值输出规则处理时环境
  struct ValueOutputParams {
    PTR<Source> source;
    PTR<Context> context;
    PTR<Name> var_name;
  };
  /// 值输出规则
  class ValueOutputRule {
  public:
    /// 根据常量赋值执行输出逻辑（比如将路径文件处理输出到编译输出目录）
    /// @param value 常量值
    /// @param params 值输出规则处理时的传入的环境参数
    virtual void performOutputAction(ConstValue& value, ValueOutputParams& params) = 0;

    /// 根据常量赋值生成输出时平台代码
    /// @param value 常量值
    /// @param params 值输出规则处理时的传入的环境参数
    virtual WString getAsOutputCode(ConstValue& value, ValueOutputParams& params) = 0;
  };

  /// 注解处理器容器
  class AnnotationManager : public Component {
  public:
    explicit AnnotationManager(const PTR<Context>& context);

    void addAnnotation(const PTR<Name>& name, const PTR<AnnotationProcessor>& processor);

    bool hasAnnotation(const PTR<Name>& name) const;

    PTR<AnnotationProcessor> getAnnotation(const PTR<Name>& name) const;

    ProcessResult processAnnotations(const TaskKind& kind, const PTR<AnnotatedTree>& tree) const;

    void addRule(const PTR<Name>& name, const PTR<ValueOutputRule>& rule);

    bool hasRule(const PTR<Name>& name) const;

    PTR<ValueOutputRule> getRule(const PTR<Name>& name) const;

    String getType() override;
    DEF_COMPONENT_FACTORY(AnnotationManager)

    /// 系统注解处理器名称
    PTR<Name> proc_static;
    PTR<Name> proc_private;
    PTR<Name> proc_virtual_method;
    PTR<Name> proc_virtual_event;
    PTR<Name> proc_force_output;
    PTR<Name> proc_forbid_new;
    PTR<Name> proc_forbid_output;
    PTR<Name> proc_global_class;
    PTR<Name> proc_inline;
    PTR<Name> proc_debug;
    PTR<Name> proc_operator_overload;
    PTR<Name> proc_auto_subscribe;
    PTR<Name> proc_async_method;
    PTR<Name> proc_deprecated;
    PTR<Name> proc_default_super_class;
    PTR<Name> proc_const_type;
    PTR<Name> proc_required_type;
    PTR<Name> proc_value_output_rule;
    PTR<Name> proc_file_pattern;
    PTR<Name> proc_output_name;
    PTR<Name> proc_alias_class;
    PTR<Name> proc_external_super_class;
    PTR<Name> proc_event_property;
  private:
    HashMap<PTR<Name>, PTR<AnnotationProcessor>, NamePtrHash, NamePtrEqual> annotation_map_;
    HashMap<PTR<Name>, PTR<ValueOutputRule>, NamePtrHash, NamePtrEqual> value_rule_map_;
    WPTR<Context> context_;

    void errorAt(const PTR<Tree>& tree, const char* key, ...) const;
  };

  class FindTreeBySymbol;
  /// Tree Api组件，提供Tree查询接口
  class TreeApi : public Component {
  public:
    explicit TreeApi(const PTR<Context>& context);

    /// 根据Symbol获取原始定义语法树
    /// @param symbol Symbol
    /// @return Symbol对应定义的语法树，可能为空
    PTR<Tree> getTree(const PTR<Symbol>& symbol) const;

    /// 根据Symbol获取语法树的TreePath
    /// @param symbol Symbol
    PTR<TreePath> getTreePath(const PTR<Symbol>& symbol) const;

    /// 根据类的完整类名获取类定义语法树
    /// @param full_name 完整类名
    /// @return 对应名称的语法树，可能为空
    PTR<ClassTree> getClassByName(const PTR<Name>& full_name) const;

    /// 获取指定被注解的语法树
    /// @param anno_name 注解名称
    List<PTR<AnnotatedTree>> getAnnotatedWith(const PTR<Name>& anno_name) const;

    /// 根据平台类名获取在结绳中的指代类
    /// @param alias_name 指代类名
    PTR<ClassTree> getAliasClass(const WString& alias_name) const;

    String getType() override;
    DEF_COMPONENT_FACTORY(TreeApi)
  private:
    WPTR<Context> context_;
    UPTR<FindTreeBySymbol> tree_finder_symbol_;
  };

  /// Symbol Api组件，提供Symbol查询接口
  class SymbolApi : public Component {
  public:
    explicit SymbolApi(const PTR<Context>& context);

    /// 根据完整类名获取ClassSymbol
    /// @param full_name 完整类名
    PTR<ClassSymbol> getClassSymbol(const PTR<Name>& full_name) const;

    /// 获取指定被注解的Symbol
    /// @param anno_name 注解名称
    List<PTR<Symbol>> getAnnotatedWith(const PTR<Name>& anno_name) const;

    /// 根据平台类名获取在结绳中的指代类ClassSymbol
    /// @param alias_name 指代类名
    PTR<ClassSymbol> getAliasClass(const WString& alias_name) const;

    String getType() override;
    DEF_COMPONENT_FACTORY(SymbolApi)
  private:
    WPTR<Context> context_;
  };

  /// 文件搜索器，用于搜索代码中指定的相对路径文件
  class FileSearcher : public Component {
  public:
    static WString kScopeSource;
    static WString kScopeLib;
    static WString kScopeRes;
    static WString kScopeAssets;

    /// 为指定Scope增加搜索前缀路径
    /// @param scope 作用域
    /// @param path 路径
    void addSearchPrefix(const WString& scope, const WString& path);

    /// 搜寻外部源文件
    /// @param current_dir 当前源代码.t文件所处目录
    /// @param relative_path 要搜寻的相对路径
    File searchSource(const WString& current_dir, const WString& relative_path);

    /// 搜寻外部依赖库
    /// @param current_dir 当前源代码.t文件所处目录
    /// @param relative_path 要搜寻的相对路径
    File searchLib(const WString& current_dir, const WString& relative_path);

    /// 搜寻安卓资源
    /// @param current_dir 当前源代码.t文件所处目录
    /// @param relative_path 要搜寻的相对路径
    File searchRes(const WString& current_dir, const WString& relative_path);

    /// 搜寻附加资源
    /// @param current_dir 当前源代码.t文件所处目录
    /// @param relative_path 要搜寻的相对路径
    File searchAssets(const WString& current_dir, const WString& relative_path);

    /// 在指定作用域下搜寻文件
    /// @param scope 作用域
    /// @param current_dir 当前源代码.t文件所处目录
    /// @param relative_path 要搜寻的相对路径
    File search(const WString& scope, const WString& current_dir, const WString& relative_path);

    String getType() override;
    DEF_COMPONENT_FACTORY(FileSearcher)
  private:
    // 每个scope的搜索路径前缀，可以有多个，搜寻不同scope的文件会把对应scope所有前缀路径都匹配一遍
    HashMap<WString, List<WString>> scope_prefixes_map_;

    /// 兼容结绳V4编译器的文件搜寻逻辑
    /// @param selected_path 相对路径
    /// @param curr_path 当前所处路径
    /// @return
    static WString finalizePathCompatV4(const WString& selected_path, const WString& curr_path);
  };

  /// 安卓平台依赖库数据结构
  struct AndroidLib {
    File file;
    bool compile_only {false};
  };

  struct AndroidLibHash {
    size_t operator()(const AndroidLib& key) const {
      return multiHash(key.file.getAbsolutePath(), key.compile_only);
    }
  };

  struct AndroidLibEqual {
    bool operator()(const AndroidLib& lhs, const AndroidLib& rhs) const {
      return lhs.file == rhs.file;
    }
  };

  using AndroidLibSet = Set<AndroidLib, AndroidLibHash, AndroidLibEqual>;
  /// 安卓平台的依赖库搜寻器接口
  class AndroidLibResolver {
  public:
    /// 依赖库搜寻逻辑
    /// @param path 依赖库路径
    /// @param messages 编译器环境中的信息输出器
    virtual AndroidLibSet resolve(const WString& path, const PTR<Messages>& messages) = 0;
  };

  /// 各平台的外部依赖库统一管理器，用于搜寻各平台代码中指定的依赖库
  class DependencyResolver : public Component {
  public:
    /// 注册一个安卓平台的依赖库搜寻器
    /// @param resolver AndroidLibResolver实例指针
    void addAndroidLibResolver(const PTR<AndroidLibResolver>& resolver);

    /// 搜寻安卓平台的依赖库
    /// @param path 依赖库路径
    AndroidLibSet resolveAndroidLib(const WString& path, const PTR<Messages>& messages);

    String getType() override;
    DEF_COMPONENT_FACTORY(DependencyResolver)
  private:
    Set<PTR<AndroidLibResolver>> android_resolvers_;
  };

  DECL_COMPONENT_NAME(Options)
  DECL_COMPONENT_NAME(NameTable)
  DECL_COMPONENT_NAME(Messages)
  DECL_COMPONENT_NAME(CompilationUnitMerger)
  DECL_COMPONENT_NAME(SourceManager)
  DECL_COMPONENT_NAME(TreeTable)
  DECL_COMPONENT_NAME(SymbolTable)
  DECL_COMPONENT_NAME(AnnotationManager)
  DECL_COMPONENT_NAME(TreeApi)
  DECL_COMPONENT_NAME(SymbolApi)
  DECL_COMPONENT_NAME(FileSearcher)
  DECL_COMPONENT_NAME(DependencyResolver)
}
#endif //TIEC_COMPONENT_H
